<script>
	import request from '@/common/request.js';
	export default {
		onLaunch: function() {
			console.log('App Launch')
		},
		onShow: function() {
			console.log('App Show: ' + this.globalData.wsOpenStatus)
			this.globalData.appHide = false;
			if(!this.globalData.wsOpenStatus && this.globalData.wsBaseUrl!='') {
				this.connectWebSocket(uni.getStorageSync('token'), this.globalData.wsBaseUrl, uni.getStorageSync('currentUser'));
			}
		},
		onHide: function() {
			console.log('App Hide: ' + this.globalData.wsOpenStatus)
			this.globalData.appHide = true;
			// uni.showToast({ title: 'App Hide: ' + this.globalData.$wsBaseUrl, icon: 'none' });
			if (this.globalData.wsOpenStatus) {
				this.globalData.webSocket.close(); // 关闭WebSocket连接
				//将之前心跳包的heartbeatTimeOutTask清除掉
				this.clearTimeOutJobs();
				// this.globalData.wsBaseUrl = '';
				this.globalData.wsOpenStatus = false;
			}
		},
		onExit: function() {
			this.globalData.appHide = true;
			if (this.globalData.wsOpenStatus) {
				this.globalData.webSocket.close(
					{
						success() {
							this.globalData.wsOpenStatus = false;
							this.globalData.webSocket = undefined;
							console.log('webSocket 关闭成功')
							uni.showToast({
								title: 'webSocket 关闭成功',
								icon: "none"
							});
						}
					}
				); // 关闭WebSocket连接
				//将之前心跳包的heartbeatTimeOutTask清除掉
				this.clearTimeOutJobs();
				this.globalData.wsOpenStatus = false;
				this.globalData.wsBaseUrl = '';
			}
		},
		globalData: {
			webSocket: undefined, // 定义全局websocketTask变量
			wsOpenStatus: false, //定义WS的连接状态
			wsBaseUrl: '', //定义WS服务端的URL
			appHide: false, //标记APP是否隐藏后台运行
			heartbeatInterval: 30000, //心跳间隔时间
			timeout: 10000, //响应超时时间
			reConnectTime: 0, //WS连续重连失败的次数
			heartbeatTimeOutTasks: [], //心跳包的重连TASK ID列表
		},
		methods: {
			connectWebSocket(token, wsUrl, currUser) {
				this.globalData.webSocket = uni.connectSocket({
					url: wsUrl,
					success: () => {
						// uni.showToast({ title: 'ws重连成功', icon: 'none' });
					}
				});
				
				this.globalData.webSocket.onOpen(() => {
					this.globalData.wsOpenStatus = true;
					this.globalData.reConnectTime = 0;
					uni.showToast({ title: 'WebSocket连接(重连)已打开!', icon: 'none' });
					this.sendToken(token, this.globalData.webSocket, true, currUser.uid);
					//开始发起发送心跳包
					this.heartbeat(token, wsUrl, currUser);
				});
				
				this.globalData.webSocket.onMessage((message) => {
					console.log('收到来自WS服务器消息：' + message.data);
					let reps = JSON.parse(message.data)
					//只有token校验才可能出现非200的code
					if(reps.code != 200) {
						uni.showToast({ title: 'Token校验失败, 登录未通过!', icon: 'none' });
						return;
					}
					//表示token校验已通过
					if (reps.msg == 'token') {
						//通知后台上线成功
						this.noticeOnlineSuccess();
					} else if (reps.msg == 'history msgs') {
						//收到的历史消息,发送消息
						console.log("离线消息....")
						uni.$emit('historyMsgs', reps.data);
					} else if (reps.msg == 'online msgs') {
						//收到的历史消息,发送消息
						console.log("在线消息....")
						//向正在被打开的聊天室页面发送对应的在线消息
						const openningChatToUid = parseInt(uni.getStorageSync('currentChat'), 10)
						if(openningChatToUid && !isNaN(openningChatToUid)) {
							let onlineMsgs = [];
							reps.data.forEach(msg => {
								//仅将该toUid发送的消息发送到聊天室页面
								if(msg.msg.userinfo.uid == openningChatToUid) {
									uni.$emit('oneOnlineMsg', msg);
								} else {
									//将其他用户发送的消息发送到好友列表页面
									onlineMsgs.push(msg)
								}
							})
							if(onlineMsgs.length>0) {
								//向好友列表页发送在线消息
								uni.$emit('onlineMsgs', onlineMsgs);
							}
						} else {
							//向好友列表页发送在线消息
							uni.$emit('onlineMsgs', reps.data);
						}
						
					} else if (reps.msg == 'pong') {
						// 收到 pong 响应，重置心跳检测
						//将之前心跳包的heartbeatTimeOutTask清除掉
						this.clearTimeOutJobs();
						setTimeout(() => this.heartbeat(token, wsUrl, currUser), this.globalData.heartbeatInterval);
					}
					
					
					
					
					
					
				});
				//连接时连接超时失败，会走这个callback
				this.globalData.webSocket.onError(() => {
					console.log('WebSocket 出现异常错误!');
					this.globalData.wsOpenStatus = false;
					// uni.showToast({ title: 'WebSocket 出现异常错误: ' + this.globalData.appHide + ":" + this.globalData.reConnectTime, icon: 'none' });
					
					//如果不是APP被hide，则需要进行重连操作. 这里reConnectTime > 0 条件表示是由heartbeatTimeOutTask发起的重连
					if(!this.globalData.appHide && this.globalData.reConnectTime < 2 && this.globalData.reConnectTime > 0) {
						setTimeout(() => {
							this.reconnectWebSocket(token, wsUrl, currUser);
							//同时将失败次数加1
							this.globalData.reConnectTime += 1;
						}, this.globalData.heartbeatInterval);
					}
					if(this.globalData.reConnectTime >= 2) {
						//将向后端请求其他空闲的MsgServer进行连接
						uni.showToast({ title: '已连续失败2次，将重新选择其他空闲服务', icon: 'none' });
						this.msgServerReChoose();
					}
				});
				
				//主动关闭，会走这个callback
				this.globalData.webSocket.onClose(() => {
					console.log('WebSocket连接被客户端关闭.');
					// uni.showToast({ title: 'WebSocket连接被客户端关闭: ' + this.globalData.appHide + ":" + this.globalData.reConnectTime, icon: 'none' });
					this.globalData.wsOpenStatus = false;
				});
			},
			sendToken(token, webSock, open, uid) {
				if(!open) {
					uni.showToast({ title: 'ws连接已关闭，无法发送token', icon: 'none' });
					return
				}
				
				const param = {
					"msgId": null,
					"messageType": "TOKEN",
					"fromUserId": uid,
					"toUserIds": null,
					"token": token,
					"msgContent": null,
					"time": 1
				}
				// uni.showToast({ title: '开始执行ws.sendToken: ' + uid, icon: 'none' });
				webSock.send({
					data: JSON.stringify(param),
					success: () => {
						console.log("前端发送Token信息到WS服务端成功.")
						// uni.showToast({ title: '前端发送Token信息到WS服务端成功: ' + uid, icon: 'none' });
					},
					fail: () => {
						uni.showToast({ title: '前端发送Token信息到WS服务端失败: ' + uid, icon: 'none' });
					}
					
				});
			},
			noticeOnlineSuccess() {
				let opts = {
					url: '/business1/talk/login/notice',
					method: 'post'
				}
				request.httpTokenRequest(opts, {}).then(reps => {
					if (reps.data.code == 200) {
						console.log("用户上线通知成功")
						//跳转到联系人页面
						uni.switchTab({
							url: "/pages/index/index",
						});
					} else {
						console.log("用户上线通知成功")
					}
				})
			
			},
			async msgServerReChoose() {
				const _this = this
				let opts = {
					url: '/server/choose',
					method: 'get'
				}
				const res = await request.httpTokenRequest(opts, {});
				if(!res.data.serverAddress) {
					uni.showToast({ title: '获取其他空闲服务信息失败!', icon: 'none' });
				} else {
					_this.globalData.wsBaseUrl = 'ws://'+ res.data.serverAddress + ':' + res.data.serverPort + '/websocket'
					_this.connectWebSocket(uni.getStorageSync('token'), _this.globalData.wsBaseUrl, uni.getStorageSync('currentUser'));
				}
			},
			// 心跳检测函数
			heartbeat(token, wsUrl, currUser) {
				// 发送心跳包
				const param = {
					"msgId": null,
					"messageType": "PONG",
					"fromUserId": currUser.uid,
					"toUserIds": null,
					"token": null,
					"msgContent": null,
					"time": 1
				}
				this.globalData.webSocket.send({data: JSON.stringify(param)});
				
				// 设置超时计时器
				const timeoutId = setTimeout(() => {
					//APP已后台运行，连接已被主动关闭，所以无需再重连
					if(this.globalData.appHide) {
						return;
					}
					console.log('心跳超时，尝试重新连接');
					// 如果超时则尝试重连
					this.globalData.webSocket.close();
					this.globalData.wsOpenStatus = false;
					if(this.globalData.reConnectTime < 2) {
						//同时将失败次数加1
						this.globalData.reConnectTime += 1;
						// 重新连接WebSocket
						this.reconnectWebSocket(token, wsUrl, currUser);
					} else {
						uni.showToast({ title: '已连续失败2次，将停止重试连接', icon: 'none' });
					}
				}, this.globalData.timeout);
				this.globalData.heartbeatTimeOutTasks.push(timeoutId);
			},
			reconnectWebSocket(token, wsUrl, currUser) {
				//尝试重新连接WS
				uni.showToast({ title: '正在重连中', icon: 'none' });
				this.connectWebSocket(token, wsUrl, currUser);
			},
			clearTimeOutJobs() {
				//将之前心跳包的heartbeatTimeOutTask清除掉
				if(this.globalData.heartbeatTimeOutTasks.length > 0) {
					this.globalData.heartbeatTimeOutTasks.forEach(item => {
						clearTimeout(item);
					})
					this.globalData.heartbeatTimeOutTasks = []
				}
			},
			
			
		},
	}
</script>

<style lang="scss">
	/*每个页面公共css */
	@import "uview-ui/index.scss";
</style>
